package com.gugee.ins.common.dal.service.spider.impl;

import com.gugee.common.exception.BizException;
import com.gugee.common.exception.SpiderRetryableException;
import com.gugee.ins.common.constant.RedisKeyConst;
import com.gugee.ins.common.dal.service.config.ServiceConfig;
import com.gugee.ins.common.dal.service.spider.SpiderSvc;
import com.gugee.ins.common.dal.spider.InsBloggerSpiderClient;
import com.gugee.ins.common.dal.spider.config.SpiderConfig;
import com.gugee.ins.common.model.spider.blogger.*;
import com.gugee.ins.data.common.constant.EventStatusEnum;
import com.gugee.ins.data.common.msg.InsBloggerMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: luolifeng
 * Date: 2021-01-07 16:16
 */
@Slf4j
@Service
public class SpiderSvcImpl implements SpiderSvc {
    /**
     * 爬虫接口
     */
    @Autowired
    InsBloggerSpiderClient insBloggerSpiderClient;

    /**
     * redis
     */
    @Autowired
    RedisTemplate<String,String> redisTemplate;

    /**
     * config
     */
    @Autowired
    SpiderConfig spiderConfig;

    /**
     * config
     */
    @Autowired
    ServiceConfig serviceConfig;

    /**
     * kafkaTemplate
     */
    @Autowired
    KafkaTemplate<Long, InsBloggerMessage> kafkaTemplateInsAnalysisAccount;

    @Override
    public FollowersInfo spiderFollowers(long uid, int totalCounts,int batchSize) {
        FollowersInfo followersInfo = new FollowersInfo();
        List<EdgeBloggerNode> followers = new ArrayList<>(totalCounts + batchSize);

        // 根据uid爬取信息
        PageInfo pageInfo;

        pageInfo = spiderFollower(uid,batchSize,"",followers);
        while(followers.size()< totalCounts && pageInfo != null && Boolean.TRUE.equals(pageInfo.getHasNextPage())
                && !StringUtils.isEmpty(pageInfo.getEndCursor())){
            pageInfo = spiderFollower(uid,batchSize,pageInfo.getEndCursor(),followers);
        }
        followersInfo.setPageInfo(pageInfo);
        if(!followers.isEmpty()){
            followersInfo.setFollowers(followers);
        }
        return followersInfo;
    }
    /**
     *  拉粉丝
     * @param uid 爬取的播主
     * @param count 每次爬取的数量
     * @param endCursor 开始爬取的位置
     * @return 返回爬取的位置信息
     */
    private PageInfo spiderFollower(long uid, int count, String endCursor, List<EdgeBloggerNode> followers){
        //根据uid爬取信息
        List<EdgeBlogger> edges;
        InsBloggerFollowedResponse insBloggerFollowedResponse;
        PageInfo pageInfo;
        try {
            insBloggerFollowedResponse = insBloggerSpiderClient.getFollowedBloggerByUid(uid,count,endCursor);
            edges = insBloggerFollowedResponse.getData().getUser().getEdgeFollow().getEdges();
            if(edges != null && !edges.isEmpty()){
                edges.forEach(edge -> {
                    if(edge != null && edge.getNode() != null
                            && !Boolean.TRUE.equals(edge.getNode().getIsPrivate())
                            && edge.getNode().getUid() != null
                            && edge.getNode().getUid() > 0){
                        followers.add(edge.getNode());
                    }
                });
            }
            pageInfo = insBloggerFollowedResponse.getData().getUser().getEdgeFollow().getPageInfo();
        }catch (Exception e){
            pageInfo = null;
            log.error("spider ins blogger follower error, msg :{}",e.getMessage());
        }
        return pageInfo;
    }

    @Override
    public FollowingInfo spiderFollowing(long uid, int totalCounts,int batchSize) {
        FollowingInfo followingInfo = new FollowingInfo();
        List<EdgeBloggerNode> followings = new ArrayList<>(totalCounts + batchSize);

        // 根据uid爬取信息
        PageInfo pageInfo;

        pageInfo = spiderFollowing(uid,batchSize,"",followings);
        while(followings.size()< totalCounts && pageInfo != null && Boolean.TRUE.equals(pageInfo.getHasNextPage())
                && !StringUtils.isEmpty(pageInfo.getEndCursor())){
            pageInfo = spiderFollower(uid,batchSize,pageInfo.getEndCursor(),followings);
        }
        followingInfo.setPageInfo(pageInfo);
        if(!followings.isEmpty()){
            followingInfo.setFollowers(followings);
        }
        return followingInfo;
    }

    /**
     * 爬取uid接口验证是否账户异常
     * @param uid
     * @return
     */
    @Override
    @Retryable(value = BizException.class, maxAttemptsExpression = "${ins.spider.insBlogger.retry:1}")
    public InsBloggerByIdResponse spiderUid4CheckSuspicious(long uid) {
        spiderSleep(RedisKeyConst.SPIDER_BLOGGER_BY_UID_4_CHECK,serviceConfig.getSpiderServiceUid4CheckSleepSecond());
        return insBloggerSpiderClient.getInsBloggerByUid(uid);
    }

    /**
     * 根据uid获取blogger基本信息
     * @param uid
     * @return
     */
    @Override
    @Retryable(value = SpiderRetryableException.class, maxAttemptsExpression = "${ins.spider.insBlogger.retry:1}")
    public InsBloggerByIdResponse getInsBloggerByUid(long uid) {
        InsBloggerByIdResponse insBloggerByIdResponse = insBloggerSpiderClient.getInsBloggerByUid(uid);

        // 发送body 404异常消息
        if(serviceConfig.getSpiderServiceCheckUidUse() != 0 && "-7404".equals(insBloggerByIdResponse.getStatus()) ){
            sendSpiderUidBodyNullMsg(uid);
        }

        if (insBloggerByIdResponse == null || insBloggerByIdResponse.getUser() == null
                || insBloggerByIdResponse.getUser().getIsPrivate() == null) {
            throw new SpiderRetryableException("get insBloggerByUid error, retry times " + spiderConfig.getSpiderRetryTimes() + ". uid:" + uid);
        }

        // 发送成功消息
        if(serviceConfig.getSpiderServiceCheckUidUse() != 0){
            sendSpiderUidSuccessMsg(uid);
        }

        return insBloggerByIdResponse;
    }
    /**
     *
     * @param uid
     * @param count
     * @param endCursor
     * @param followings
     * @return
     */
    private PageInfo spiderFollowing(long uid, int count, String endCursor, List<EdgeBloggerNode> followings){
        //根据uid爬取信息
        List<EdgeBlogger> edges;
        InsBloggerFollowingResponse insBloggerFollowingResponse;
        PageInfo pageInfo;
        try {
            insBloggerFollowingResponse = insBloggerSpiderClient.getFollowingBloggerByUid(uid,count,endCursor);
            edges = insBloggerFollowingResponse.getData().getUser().getEdgeFollow().getEdges();
            if(edges != null && !edges.isEmpty()){
                edges.forEach(edge -> {
                    if(edge != null && edge.getNode() != null
                            && !Boolean.TRUE.equals(edge.getNode().getIsPrivate())
                            && edge.getNode().getUid() != null
                            && edge.getNode().getUid() > 0){
                        followings.add(edge.getNode());
                    }
                });
            }
            pageInfo = insBloggerFollowingResponse.getData().getUser().getEdgeFollow().getPageInfo();
        }catch (Exception e){
            pageInfo = null;
            log.error("spider ins blogger follower error, msg :{}",e.getMessage());
        }
        return pageInfo;
    }

    /**
     * 爬完就睡眠 防止风控
     */
    private void spiderSleep(String redisKey,long ms){
        if(ms > 0) {
            while (isSleep(redisKey,ms)) {
                //睡眠
                try {
                    Thread.sleep(ms);
                } catch (Exception e) {
                    log.error("spider sleep error,msg:{}",e.getMessage());
                }
            }
        }
    }

    /**
     *
     * @param redisKey
     * @param ms
     * @return
     */
    private boolean isSleep(String redisKey,long ms){
        return !redisTemplate.opsForValue().setIfAbsent(redisKey, System.currentTimeMillis() + "", ms, TimeUnit.MILLISECONDS);
    }

    /**
     * 发送爬取uid接口 body 异常消息
     * @param uid
     */
    private void sendSpiderUidBodyNullMsg(long uid){
        try{
            InsBloggerMessage insBloggerMessage = new InsBloggerMessage();
            insBloggerMessage.setUid(uid);
            kafkaTemplateInsAnalysisAccount.send(serviceConfig.getInsBloggerAccountUnusualOnlineTopic(),insBloggerMessage);
        }catch (Exception e){
            log.error("send InsBloggerAccountUnusual msg error,uid:{},msg:{}",uid,e.getMessage());
        }
    }

    /**
     * 发送爬取uid接口 成功 消息
     * @param uid
     */
    private void sendSpiderUidSuccessMsg(long uid){
        try{
            InsBloggerMessage insBloggerMessage = new InsBloggerMessage();
            insBloggerMessage.setUid(uid);
            kafkaTemplateInsAnalysisAccount.send(serviceConfig.getInsBloggerAccountNormalOnlineTopic(),insBloggerMessage);
        }catch (Exception e){
            log.error("send InsBloggerAccountNormal msg error,uid:{},msg:{}",uid,e.getMessage());
        }
    }
}
